package com.axinfu.util.http;

import com.axinfu.util.EmptyUtil;
import com.axinfu.util.http.response.HttpResponseResult;
import com.axinfu.util.http.response.ResponseHandler;
import com.axinfu.util.http.response.StringHttpResponseResult;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * HttpUtil
 *
 * @author zjn
 * @since 2022/3/23
 */
@SuppressWarnings("unused")
public class HttpUtil {

    private static final HttpClient HTTP_CLIENT;
    private static final RequestConfig REQUEST_CONFIG;
    private static final CookieStore COOKIE_STORE;

    private static final Map<String, HttpPrintConfig> PRINT_CONFIG_MAP = new HashMap<>();

    private HttpUtil() {
    }

    static {
        try {
            SSLContextBuilder builder = SSLContextBuilder.create();
            // 全部信任 不做身份鉴定
            builder.loadTrustMaterial(null, (TrustStrategy) (x509Certificates, s) -> true);

            SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(builder.build(),
                    new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"},
                    null, NoopHostnameVerifier.INSTANCE);

            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", new PlainConnectionSocketFactory())
                    .register("https", sslcsf)
                    .build();

            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
            cm.setMaxTotal(2000);
            cm.setDefaultMaxPerRoute(1000);

            COOKIE_STORE = new BasicCookieStore();

            HTTP_CLIENT = HttpClients.custom()
                    .setSSLHostnameVerifier((s, sslSession) -> true)
                    .setSSLSocketFactory(sslcsf)
                    .setConnectionManager(cm)
                    .setConnectionManagerShared(true)
                    .setDefaultCookieStore(COOKIE_STORE)
                    .build();

            REQUEST_CONFIG = RequestConfig.custom()
                    .setConnectionRequestTimeout(30000)
                    .setConnectTimeout(30000)
                    .setSocketTimeout(300000)
                    .build();

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static HttpClient getHttpClient() {
        return HTTP_CLIENT;
    }

    public static RequestConfig getRequestConfig() {
        return REQUEST_CONFIG;
    }

    public static CookieStore getCookieStore() {
        return COOKIE_STORE;
    }

    /**
     * 设置打印配置
     *
     * @param url             url
     * @param httpPrintConfig 打印配置
     */
    public static void setPrintConfig(String url, HttpPrintConfig httpPrintConfig) {
        PRINT_CONFIG_MAP.put(url, httpPrintConfig);
    }

    /**
     * 移除打印配置
     *
     * @param url url
     */
    public static void removePrintConfig(String url) {
        PRINT_CONFIG_MAP.remove(url);
    }

    /**
     * 清除打印配置
     */
    public static void clearPrintConfig() {
        PRINT_CONFIG_MAP.clear();
    }

    /**
     * 获取url匹配到的打印日志配置
     *
     * @param url 请求url
     * @return HttpPrintConfig
     */
    public static HttpPrintConfig isMatchPrintLog(String url) {
        for (Map.Entry<String, HttpPrintConfig> entry : PRINT_CONFIG_MAP.entrySet()) {
            String key = entry.getKey();
            if (url.startsWith(key)) {
                return entry.getValue();
            }
        }
        return null;
    }

    /**
     * 发送请求
     *
     * @param httpClient      httpClient
     * @param requestConfig   requestConfig
     * @param cookieStore     cookieStore
     * @param httpMethod      请求方法
     * @param url             请求地址
     * @param queryParamMap   url参数
     * @param headerMap       header参数
     * @param bodyEntity      body内容
     * @param responseHandler 结果解析器
     * @param <T>             返回结果类
     * @return 返回结果
     */
    @SuppressWarnings("unchecked")
    public static <T extends HttpResponseResult> T reqeust(HttpClient httpClient, RequestConfig requestConfig,
                                                           CookieStore cookieStore,
                                                           String httpMethod, String url,
                                                           Map<String, String> queryParamMap,
                                                           Map<String, String> headerMap, HttpEntity bodyEntity,
                                                           ResponseHandler<? extends HttpResponseResult> responseHandler) {
        HttpPrintConfig httpPrintConfig = isMatchPrintLog(url);
        boolean isPrintLog = false;
        boolean isPrintFile = false;
        String printFilePath = null;
        if (EmptyUtil.isNotEmpty(httpPrintConfig)) {
            isPrintLog = httpPrintConfig.isPrintLog();
            isPrintFile = httpPrintConfig.isPrintFile();
            printFilePath = httpPrintConfig.getPrintFilePath();
        }
        return (T) HttpRequester.create(httpClient, requestConfig, cookieStore)
                .setHttpMethod(httpMethod)
                .setUrl(url)
                .addQueryParams(queryParamMap)
                .addHeaders(headerMap)
                .setBodyEntity(bodyEntity)
                .setResponseHandler(responseHandler)
                .setPrintLog(isPrintLog)
                .setPrintFile(isPrintFile)
                .setPrintFilePath(printFilePath)
                .execute();
    }

    /**
     * 发送请求
     *
     * @param httpMethod      请求方法
     * @param url             请求地址
     * @param queryParamMap   url参数
     * @param headerMap       header参数
     * @param bodyEntity      body内容
     * @param responseHandler 结果解析器
     * @param <T>             返回结果类
     * @return 返回结果
     */
    public static <T extends HttpResponseResult> T reqeust(String httpMethod, String url,
                                                           Map<String, String> queryParamMap,
                                                           Map<String, String> headerMap, HttpEntity bodyEntity,
                                                           ResponseHandler<? extends HttpResponseResult> responseHandler) {
        return reqeust(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, httpMethod, url, queryParamMap, headerMap, bodyEntity,
                responseHandler);
    }

    /**
     * 发送请求
     *
     * @param httpMethod               请求方法
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyEntity               body内容
     * @param responseHandler          结果解析器
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @param <T>                      返回结果类
     * @return 返回结果
     */
    public static <T extends HttpResponseResult> T reqeust(String httpMethod, String url,
                                                           Map<String, String> queryParamMap,
                                                           Map<String, String> headerMap, HttpEntity bodyEntity,
                                                           ResponseHandler<? extends HttpResponseResult> responseHandler,
                                                           int connectionRequestTimeout,
                                                           int connectTimeout,
                                                           int socketTimeout
    ) {
        return reqeust(HTTP_CLIENT, RequestConfig.custom()
                        .setConnectionRequestTimeout(connectionRequestTimeout)
                        .setConnectTimeout(connectTimeout)
                        .setSocketTimeout(socketTimeout)
                        .build(), COOKIE_STORE, httpMethod, url, queryParamMap, headerMap, bodyEntity,
                responseHandler);
    }

    /**
     * 发送get请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult get(HttpClient httpClient, RequestConfig requestConfig,
                                               CookieStore cookieStore, String url, Map<String, String> queryParamMap
            , Map<String, String> headerMap) {
        return reqeust(httpClient, requestConfig, cookieStore, HttpGet.METHOD_NAME, url,
                queryParamMap, headerMap, null, null);
    }

    /**
     * 发送get请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult get(String url, Map<String, String> queryParamMap,
                                               Map<String, String> headerMap) {
        return get(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送get请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult get(String url, Map<String, String> queryParamMap,
                                               Map<String, String> headerMap,
                                               int connectionRequestTimeout,
                                               int connectTimeout,
                                               int socketTimeout) {
        return get(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送post请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult post(HttpClient httpClient, RequestConfig requestConfig,
                                                CookieStore cookieStore, String url,
                                                Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                Map<String, Object> bodyParamMap) {
        try {
            List<NameValuePair> list = new ArrayList<>();
            for (Map.Entry<String, Object> stringStringEntry : bodyParamMap.entrySet()) {
                list.add(new BasicNameValuePair(stringStringEntry.getKey(), stringStringEntry.getValue().toString()));
            }
            UrlEncodedFormEntity bodyEntity = new UrlEncodedFormEntity(list, "UTF-8");
            return reqeust(httpClient, requestConfig, cookieStore, HttpPost.METHOD_NAME,
                    url, queryParamMap, headerMap, bodyEntity, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送post请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, Map<String, Object> bodyParamMap) {
        return post(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap);
    }

    /**
     * 发送post请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamMap             body内容
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, Map<String, Object> bodyParamMap,
                                                int connectionRequestTimeout,
                                                int connectTimeout,
                                                int socketTimeout) {
        return post(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap);
    }

    // ==========================================
    // ==========================================
    // ==========================================

    /**
     * 发送post请求
     *
     * @param httpClient     httpClient
     * @param requestConfig  requestConfig
     * @param cookieStore    cookieStore
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamBytes body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult post(HttpClient httpClient, RequestConfig requestConfig,
                                                CookieStore cookieStore, String url,
                                                Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                byte[] bodyParamBytes) {
        ByteArrayEntity bodyEntity = new ByteArrayEntity(bodyParamBytes);
        return reqeust(httpClient, requestConfig, cookieStore, HttpPost.METHOD_NAME, url,
                queryParamMap, headerMap, bodyEntity, null);
    }

    /**
     * 发送post请求
     *
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamBytes body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, byte[] bodyParamBytes) {
        return post(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamBytes);
    }

    /**
     * 发送post请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamBytes           body内容
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, byte[] bodyParamBytes,
                                                int connectionRequestTimeout,
                                                int connectTimeout,
                                                int socketTimeout) {
        return post(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamBytes);
    }

    /**
     * 发送post请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @param fileMap       文件map
     * @return 返回结果
     */
    public static StringHttpResponseResult post(HttpClient httpClient, RequestConfig requestConfig,
                                                CookieStore cookieStore, String url,
                                                Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                Map<String, Object> bodyParamMap, Map<String, File> fileMap) {
        try {
            MultipartEntityBuilder multipartEntityBuilder = getMultipartEntityBuilder(fileMap);
            if (bodyParamMap != null && bodyParamMap.size() > 0) {
                for (Map.Entry<String, Object> entry : bodyParamMap.entrySet()) {
                    multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue().toString());
                }
            }
            HttpEntity bodyEntity = multipartEntityBuilder.build();

            return reqeust(httpClient, requestConfig, cookieStore, HttpPost.METHOD_NAME,
                    url, queryParamMap, headerMap, bodyEntity, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送post请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @param fileMap       文件map
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, Map<String, Object> bodyParamMap,
                                                Map<String, File> fileMap) {
        return post(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap, fileMap);
    }

    /**
     * 发送post请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamMap             body内容
     * @param fileMap                  文件map
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, Map<String, Object> bodyParamMap,
                                                Map<String, File> fileMap,
                                                int connectionRequestTimeout,
                                                int connectTimeout,
                                                int socketTimeout) {
        return post(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap, fileMap);
    }

    /**
     * 发送post请求
     *
     * @param httpClient     httpClient
     * @param requestConfig  requestConfig
     * @param cookieStore    cookieStore
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamName  body参数名称
     * @param bodyParamBytes body内容
     * @param fileMap        文件map
     * @return 返回结果
     */
    public static StringHttpResponseResult post(HttpClient httpClient, RequestConfig requestConfig,
                                                CookieStore cookieStore, String url,
                                                Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                String bodyParamName, byte[] bodyParamBytes,
                                                Map<String, File> fileMap) {
        try {
            MultipartEntityBuilder multipartEntityBuilder = getMultipartEntityBuilder(fileMap);
            multipartEntityBuilder.addBinaryBody(bodyParamName, bodyParamBytes);
            HttpEntity bodyEntity = multipartEntityBuilder.build();
            return reqeust(httpClient, requestConfig, cookieStore, HttpPost.METHOD_NAME,
                    url, queryParamMap, headerMap, bodyEntity, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送post请求
     *
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamName  body参数名称
     * @param bodyParamBytes body内容
     * @param fileMap        文件map
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, String bodyParamName,
                                                byte[] bodyParamBytes, Map<String, File> fileMap) {
        return post(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamName,
                bodyParamBytes, fileMap);
    }

    /**
     * 发送post请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamName            body参数名称
     * @param bodyParamBytes           body内容
     * @param fileMap                  文件map
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, String bodyParamName,
                                                byte[] bodyParamBytes, Map<String, File> fileMap,
                                                int connectionRequestTimeout,
                                                int connectTimeout,
                                                int socketTimeout) {
        return post(HTTP_CLIENT, RequestConfig.custom()
                        .setConnectionRequestTimeout(connectionRequestTimeout)
                        .setConnectTimeout(connectTimeout)
                        .setSocketTimeout(socketTimeout)
                        .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamName,
                bodyParamBytes, fileMap);
    }

    /**
     * 发送post请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @param fileName      文件名
     * @param file          文件
     * @return 返回结果
     */
    public static StringHttpResponseResult post(HttpClient httpClient, RequestConfig requestConfig,
                                                CookieStore cookieStore, String url,
                                                Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                Map<String, Object> bodyParamMap, String fileName, File file) {
        Map<String, File> fileMap = new HashMap<>(1);
        fileMap.put(fileName, file);
        return post(httpClient, requestConfig, cookieStore, url, queryParamMap, headerMap, bodyParamMap, fileMap);
    }

    /**
     * 发送post请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @param fileName      文件名
     * @param file          文件
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, Map<String, Object> bodyParamMap,
                                                String fileName, File file) {
        return post(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap, fileName,
                file);
    }

    /**
     * 发送post请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamMap             body内容
     * @param fileName                 文件名
     * @param file                     文件
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, Map<String, Object> bodyParamMap,
                                                String fileName, File file,
                                                int connectionRequestTimeout,
                                                int connectTimeout,
                                                int socketTimeout) {
        return post(HTTP_CLIENT, RequestConfig.custom()
                        .setConnectionRequestTimeout(connectionRequestTimeout)
                        .setConnectTimeout(connectTimeout)
                        .setSocketTimeout(socketTimeout)
                        .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap, fileName,
                file);
    }

    /**
     * 发送post请求
     *
     * @param httpClient     httpClient
     * @param requestConfig  requestConfig
     * @param cookieStore    cookieStore
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamName  body参数名称
     * @param bodyParamBytes body内容
     * @param fileName       文件名
     * @param file           文件
     * @return 返回结果
     */
    public static StringHttpResponseResult post(HttpClient httpClient, RequestConfig requestConfig,
                                                CookieStore cookieStore, String url,
                                                Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                String bodyParamName, byte[] bodyParamBytes, String fileName,
                                                File file) {
        Map<String, File> fileMap = new HashMap<>(1);
        fileMap.put(fileName, file);
        return post(httpClient, requestConfig, cookieStore, url, queryParamMap, headerMap, bodyParamName,
                bodyParamBytes, fileMap);
    }

    /**
     * 发送post请求
     *
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamName  body参数名称
     * @param bodyParamBytes body内容
     * @param fileName       文件名
     * @param file           文件
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, String bodyParamName,
                                                byte[] bodyParamBytes, String fileName, File file) {
        return post(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamName,
                bodyParamBytes, fileName, file);
    }

    /**
     * 发送post请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamName            body参数名称
     * @param bodyParamBytes           body内容
     * @param fileName                 文件名
     * @param file                     文件
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult post(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap, String bodyParamName,
                                                byte[] bodyParamBytes, String fileName, File file,
                                                int connectionRequestTimeout,
                                                int connectTimeout,
                                                int socketTimeout) {
        return post(HTTP_CLIENT, RequestConfig.custom()
                        .setConnectionRequestTimeout(connectionRequestTimeout)
                        .setConnectTimeout(connectTimeout)
                        .setSocketTimeout(socketTimeout)
                        .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamName,
                bodyParamBytes, fileName, file);
    }

    /**
     * 发送put请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult put(HttpClient httpClient, RequestConfig requestConfig,
                                               CookieStore cookieStore, String url, Map<String, String> queryParamMap
            , Map<String, String> headerMap, Map<String, Object> bodyParamMap) {
        return requestResult(httpClient, requestConfig, cookieStore, url, HttpPut.METHOD_NAME,
                queryParamMap,
                headerMap,
                bodyParamMap);
    }

    /**
     * 发送put请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult put(String url, Map<String, String> queryParamMap,
                                               Map<String, String> headerMap, Map<String, Object> bodyParamMap) {
        return put(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap);
    }

    /**
     * 发送put请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamMap             body内容
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult put(String url, Map<String, String> queryParamMap,
                                               Map<String, String> headerMap, Map<String, Object> bodyParamMap,
                                               int connectionRequestTimeout,
                                               int connectTimeout,
                                               int socketTimeout) {
        return put(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap);
    }

    /**
     * 发送put请求
     *
     * @param httpClient     httpClient
     * @param requestConfig  requestConfig
     * @param cookieStore    cookieStore
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamBytes body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult put(HttpClient httpClient, RequestConfig requestConfig,
                                               CookieStore cookieStore, String url, Map<String, String> queryParamMap
            , Map<String, String> headerMap, byte[] bodyParamBytes) {
        ByteArrayEntity bodyEntity = new ByteArrayEntity(bodyParamBytes);
        return reqeust(httpClient, requestConfig, cookieStore, HttpPut.METHOD_NAME, url,
                queryParamMap, headerMap, bodyEntity, null);
    }

    /**
     * 发送put请求
     *
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamBytes body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult put(String url, Map<String, String> queryParamMap,
                                               Map<String, String> headerMap, byte[] bodyParamBytes) {
        return put(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamBytes);
    }

    /**
     * 发送put请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamBytes           body内容
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult put(String url, Map<String, String> queryParamMap,
                                               Map<String, String> headerMap, byte[] bodyParamBytes,
                                               int connectionRequestTimeout,
                                               int connectTimeout,
                                               int socketTimeout) {
        return put(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamBytes);
    }

    /**
     * 发送head请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult head(HttpClient httpClient, RequestConfig requestConfig,
                                                CookieStore cookieStore, String url,
                                                Map<String, String> queryParamMap, Map<String, String> headerMap) {
        return reqeust(httpClient, requestConfig, cookieStore, HttpHead.METHOD_NAME, url,
                queryParamMap, headerMap, null, null);
    }

    /**
     * 发送head请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult head(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap) {
        return head(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送head请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult head(String url, Map<String, String> queryParamMap,
                                                Map<String, String> headerMap,
                                                int connectionRequestTimeout,
                                                int connectTimeout,
                                                int socketTimeout) {
        return head(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送delete请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult delete(HttpClient httpClient, RequestConfig requestConfig,
                                                  CookieStore cookieStore, String url,
                                                  Map<String, String> queryParamMap, Map<String, String> headerMap) {
        return reqeust(httpClient, requestConfig, cookieStore, HttpDelete.METHOD_NAME, url
                , queryParamMap, headerMap, null, null);
    }

    /**
     * 发送delete请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult delete(String url, Map<String, String> queryParamMap,
                                                  Map<String, String> headerMap) {
        return delete(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送delete请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult delete(String url, Map<String, String> queryParamMap,
                                                  Map<String, String> headerMap,
                                                  int connectionRequestTimeout,
                                                  int connectTimeout,
                                                  int socketTimeout) {
        return delete(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送patch请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult patch(HttpClient httpClient, RequestConfig requestConfig,
                                                 CookieStore cookieStore, String url,
                                                 Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                 Map<String, Object> bodyParamMap) {
        return requestResult(httpClient, requestConfig, cookieStore, url, HttpPatch.METHOD_NAME,
                queryParamMap,
                headerMap,
                bodyParamMap);
    }

    /**
     * 发送patch请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @param bodyParamMap  body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult patch(String url, Map<String, String> queryParamMap,
                                                 Map<String, String> headerMap, Map<String, Object> bodyParamMap) {
        return patch(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap);
    }

    /**
     * 发送patch请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamMap             body内容
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult patch(String url, Map<String, String> queryParamMap,
                                                 Map<String, String> headerMap, Map<String, Object> bodyParamMap,
                                                 int connectionRequestTimeout,
                                                 int connectTimeout,
                                                 int socketTimeout) {
        return patch(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamMap);
    }

    /**
     * 发送patch请求
     *
     * @param httpClient     httpClient
     * @param requestConfig  requestConfig
     * @param cookieStore    cookieStore
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamBytes body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult patch(HttpClient httpClient, RequestConfig requestConfig,
                                                 CookieStore cookieStore, String url,
                                                 Map<String, String> queryParamMap, Map<String, String> headerMap,
                                                 byte[] bodyParamBytes) {
        ByteArrayEntity bodyEntity = new ByteArrayEntity(bodyParamBytes);
        return reqeust(httpClient, requestConfig, cookieStore, HttpPatch.METHOD_NAME, url,
                queryParamMap, headerMap, bodyEntity, null);
    }

    /**
     * 发送patch请求
     *
     * @param url            请求地址
     * @param queryParamMap  url参数
     * @param headerMap      header参数
     * @param bodyParamBytes body内容
     * @return 返回结果
     */
    public static StringHttpResponseResult patch(String url, Map<String, String> queryParamMap,
                                                 Map<String, String> headerMap, byte[] bodyParamBytes) {
        return patch(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap, bodyParamBytes);
    }

    /**
     * 发送patch请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param bodyParamBytes           body内容
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult patch(String url, Map<String, String> queryParamMap,
                                                 Map<String, String> headerMap, byte[] bodyParamBytes,
                                                 int connectionRequestTimeout,
                                                 int connectTimeout,
                                                 int socketTimeout) {
        return patch(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap, bodyParamBytes);
    }

    /**
     * 发送options请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult options(HttpClient httpClient, RequestConfig requestConfig,
                                                   CookieStore cookieStore, String url,
                                                   Map<String, String> queryParamMap, Map<String, String> headerMap) {
        return reqeust(httpClient, requestConfig, cookieStore, HttpOptions.METHOD_NAME,
                url, queryParamMap, headerMap, null, null);
    }

    /**
     * 发送options请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult options(String url, Map<String, String> queryParamMap,
                                                   Map<String, String> headerMap) {
        return options(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送options请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult options(String url, Map<String, String> queryParamMap,
                                                   Map<String, String> headerMap,
                                                   int connectionRequestTimeout,
                                                   int connectTimeout,
                                                   int socketTimeout) {
        return options(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送trace请求
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult trace(HttpClient httpClient, RequestConfig requestConfig,
                                                 CookieStore cookieStore, String url,
                                                 Map<String, String> queryParamMap, Map<String, String> headerMap) {
        return reqeust(httpClient, requestConfig, cookieStore, HttpTrace.METHOD_NAME, url,
                queryParamMap, headerMap, null, null);
    }

    /**
     * 发送trace请求
     *
     * @param url           请求地址
     * @param queryParamMap url参数
     * @param headerMap     header参数
     * @return 返回结果
     */
    public static StringHttpResponseResult trace(String url, Map<String, String> queryParamMap,
                                                 Map<String, String> headerMap) {
        return trace(HTTP_CLIENT, REQUEST_CONFIG, COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 发送trace请求
     *
     * @param url                      请求地址
     * @param queryParamMap            url参数
     * @param headerMap                header参数
     * @param connectionRequestTimeout connectionRequestTimeout
     * @param connectTimeout           connectTimeout
     * @param socketTimeout            socketTimeout
     * @return 返回结果
     */
    public static StringHttpResponseResult trace(String url, Map<String, String> queryParamMap,
                                                 Map<String, String> headerMap,
                                                 int connectionRequestTimeout,
                                                 int connectTimeout,
                                                 int socketTimeout) {
        return trace(HTTP_CLIENT, RequestConfig.custom()
                .setConnectionRequestTimeout(connectionRequestTimeout)
                .setConnectTimeout(connectTimeout)
                .setSocketTimeout(socketTimeout)
                .build(), COOKIE_STORE, url, queryParamMap, headerMap);
    }

    /**
     * 构建url参数
     *
     * @param queryParamMap url参数map
     * @param isEncode      value是否编码
     * @return url的键值对字符串
     */
    public static String getQueryString(Map<String, String> queryParamMap, boolean isEncode) {
        if (EmptyUtil.isEmpty(queryParamMap)) {
            return null;
        }

        StringBuilder querySb = new StringBuilder();
        for (Map.Entry<String, String> entry : queryParamMap.entrySet()) {
            String k = entry.getKey().trim();
            String v = entry.getValue().trim();
            if (isEncode) {
                try {
                    v = URLEncoder.encode(v, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException(e);
                }
            }
            querySb.append("&").append(k).append("=").append(v);
        }
        return querySb.length() > 0 ? querySb.substring(1) : querySb.toString();
    }

    /**
     * 构建url参数
     *
     * @param queryParamMap url参数map
     * @return url的键值对字符串
     */
    public static String getQueryString(Map<String, String> queryParamMap) {
        return getQueryString(queryParamMap, false);
    }

    /**
     * 自动将map中的参数组装到url中
     *
     * @param url           url
     * @param queryParamMap 参数
     * @param isEncode      参数值是否编码
     * @return 组装后的url
     */
    public static String urlBuildQueryString(String url, Map<String, String> queryParamMap, boolean isEncode) {
        if (EmptyUtil.isEmpty(queryParamMap)) {
            return url;
        }

        String queryStr = getQueryString(queryParamMap, isEncode);
        String queryStrChar = url.indexOf("?") > 0 ? "&" : "?";
        return url + queryStrChar + queryStr;
    }

    /**
     * 自动将map中的参数组装到url中
     *
     * @param url           url
     * @param queryParamMap 参数
     * @return 组装后的url
     */
    public static String urlBuildQueryString(String url, Map<String, String> queryParamMap) {
        return urlBuildQueryString(url, queryParamMap, false);
    }


    /**
     * 解析url
     *
     * @param url url地址
     * @return 解析结果
     */
    public static UrlEntity parseUrl(String url) {
        UrlEntity entity = new UrlEntity();

        if (EmptyUtil.isEmpty(url)) {
            return entity;
        }

        url = url.trim();
        String[] urlParts = url.split("\\?");
        entity.setBaseUrl(urlParts[0]);

        //没有参数
        if (urlParts.length == 1) {
            return entity;
        }

        //有参数
        String[] params = urlParts[1].split("&");
        for (String param : params) {
            String[] keyValue = param.split("=");
            entity.getParams().put(keyValue[0], keyValue[1]);
        }

        return entity;
    }

    /**
     * UrlEntity
     */
    public static class UrlEntity {

        /**
         * baseUrl
         */
        private String baseUrl;

        /**
         * params
         */
        private Map<String, String> params = new HashMap<>();

        public String getParam(String name) {
            return params.get(name);
        }

        public String getBaseUrl() {
            return baseUrl;
        }

        public void setBaseUrl(String baseUrl) {
            this.baseUrl = baseUrl;
        }

        public Map<String, String> getParams() {
            return params;
        }

        public void setParams(Map<String, String> params) {
            this.params = params;
        }
    }

    /**
     * requestResult
     *
     * @param httpClient    httpClient
     * @param requestConfig requestConfig
     * @param cookieStore   cookieStore
     * @param url           url
     * @param method        method
     * @param queryParamMap queryParamMap
     * @param headerMap     headerMap
     * @param bodyParamMap  bodyParamMap
     * @return StringHttpResponseResult
     */
    private static StringHttpResponseResult requestResult(HttpClient httpClient,
                                                          RequestConfig requestConfig,
                                                          CookieStore cookieStore,
                                                          String url, String method,
                                                          Map<String, String> queryParamMap,
                                                          Map<String, String> headerMap,
                                                          Map<String, Object> bodyParamMap) {
        try {
            List<NameValuePair> list = new ArrayList<>();
            for (Map.Entry<String, Object> stringStringEntry : bodyParamMap.entrySet()) {
                list.add(new BasicNameValuePair(stringStringEntry.getKey(), stringStringEntry.getValue().toString()));
            }
            UrlEncodedFormEntity bodyEntity = new UrlEncodedFormEntity(list);
            return reqeust(httpClient, requestConfig, cookieStore, method,
                    url, queryParamMap, headerMap, bodyEntity, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * getMultipartEntityBuilder
     *
     * @param fileMap fileMap
     * @return MultipartEntityBuilder
     * @throws UnsupportedEncodingException UnsupportedEncodingException
     */
    private static MultipartEntityBuilder getMultipartEntityBuilder(Map<String, File> fileMap) throws UnsupportedEncodingException {
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
        if (fileMap != null && fileMap.size() > 0) {
            for (Map.Entry<String, File> entry : fileMap.entrySet()) {
                String paramName = entry.getKey();
                File file = entry.getValue();
                String fileName = file.getName();
                fileName = URLEncoder.encode(fileName, "UTF-8");
                ContentType contentType = ContentType.create("application/octet-stream", "UTF-8");
                multipartEntityBuilder.addBinaryBody(paramName, file, contentType, fileName);
            }
        }
        return multipartEntityBuilder;
    }
}
